﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using XGameLibrary;
using XGameLibrary.Character;
using XGameLibrary.Sprite;
using XGameLibrary.PathFind;
using XGameLibrary.Controls;
using TomShane.Neoforce.Controls;



namespace XGame.Class
{
    public class Player
    {
        #region 身份属性

        public enum PKModes
        {
            /// <summary>
            /// 和平模式
            /// </summary>
            Peace = 0,
            /// <summary>
            /// 全体模式
            /// </summary>
            Whole = 1,
            /// <summary>
            /// 善恶模式
            /// </summary>
            GoodAndEvil = 2,
            /// <summary>
            /// 门派模式
            /// </summary>
            Faction = 3,
            /// <summary>
            /// 家族模式
            /// </summary>
            Clan = 4,
        }

        /// <summary>
        /// 获取或设置头像代号
        /// </summary>
        public int FaceSign;

        /// <summary>
        /// 获取或设置PK模式
        /// </summary>
        public PKModes PKMode;

        /// <summary>
        /// 获取或设置门派名
        /// </summary>
        public string VFaction;

        /// <summary>
        /// 获取或设置家族名
        /// </summary>
        public string VClan;

        /// <summary>
        /// 获取或设置姓名
        /// </summary>
        public string VSName;

        #endregion

        #region 基本值属性

        /// <summary>
        /// 获取或设置被附加属性对应伤害效果
        /// </summary>
        public double[] AdditionalEffect;

        /// <summary>
        /// 获取或设置被附加属性对应持续时间
        /// </summary>
        public double[] AdditionalEffectTime;

        /// <summary>
        /// 获取或设置对该精灵给予持续性魔法伤害的对象精灵名
        /// </summary>
        public string AdditionalEffectSprite;

        /// <summary>
        /// 获取或设置等级
        /// </summary>
        public int VLevel;

        /// <summary>
        /// 获取或设置自身的经验值(如果为怪物等NPC,则为杀它的玩家可以得到的经验值)
        /// </summary>
        public int VExperience;

        /// <summary>
        /// PK值(正值代表善良,负值代表邪恶, 正负7之间)
        /// </summary>
        public int VPK;

        /// <summary>
        /// 获取最大负重
        /// </summary>
        public double VBurdenMax
        {
            get { return ABase[0] + Equip[0] + Buff[0] + VPower * Coefficient[0]; }
        }

        /// <summary>
        /// 获取物理攻击力最小值
        /// </summary>
        public double VAttackMin
        {
            get { return ABase[1] + Equip[1] + Buff[1] + VPower * Coefficient[1]; }
        }

        /// <summary>
        /// 获取物理攻击力最大值
        /// </summary>
        public double VAttackMax
        {
            get { return ABase[2] + Equip[2] + Buff[2] + VPower * Coefficient[2]; }
        }

        /// <summary>
        /// 获取命中值
        /// </summary>
        public double VHit
        {
            get { return ABase[3] + Equip[3] + Buff[3] + VAgile * Coefficient[3]; }
        }

        /// <summary>
        /// 获取闪避值
        /// </summary>
        public double VDodge
        {
            get { return ABase[4] + Equip[4] + Buff[4] + VAgile * Coefficient[4]; }
        }

        /// <summary>
        /// 获取跑步速度(每移动一个单元格的花费时间,越小越快)
        /// </summary>
        public double VRunSpeed
        {
            get { return ABase[5] + Equip[5] + Buff[5] - VAgile * Coefficient[5]; }
        }

        /// <summary>
        /// 获取物攻速度(越小越快)
        /// </summary>
        public double VAttackSpeed
        {
            get { return ABase[6] + Equip[6] + Buff[6] - VAgile * Coefficient[6]; }
        }

        /// <summary>
        /// 获取施法速度(越小越快)
        /// </summary>
        public double VMagicSpeed
        {
            get { return ABase[7] + Equip[7] + Buff[7] - VAgile * Coefficient[7]; }
        }

        /// <summary>
        /// 获取或设置当前生命值
        /// </summary>
        public double VLife { get; set; }

        /// <summary>
        /// 获取最大生命值
        /// </summary>
        public double VLifeMax
        {
            get { return ABase[8] + Equip[8] + Buff[8] + VPhysique * Coefficient[8]; }
        }

        /// <summary>
        /// 获取物理防御力
        /// </summary>
        public double VDefense
        {
            get { return ABase[9] + Equip[9] + Buff[9] + VPhysique * Coefficient[9]; }
        }

        /// <summary>
        /// 获取格档率
        /// </summary>
        public double VBlock
        {
            get { return ABase[10] + Equip[10] + Buff[10] + VPhysique * Coefficient[10]; }
        }

        /// <summary>
        /// 获取或设置当前魔法值
        /// </summary>
        public double VMana { get; set; }

        /// <summary>
        /// 获取最大魔法值
        /// </summary>
        public double VManaMax
        {
            get { return ABase[11] + Equip[11] + Buff[11] + VWisdom * Coefficient[11]; }
        }

        /// <summary>
        /// 获取魔法防御力
        /// </summary>
        public double VMagicDefense
        {
            get { return ABase[12] + Equip[12] + Buff[12] + VWisdom * Coefficient[12]; }
        }

        /// <summary>
        /// 获取魔法攻击力最小值
        /// </summary>
        public double VMagicMin
        {
            get { return ABase[13] + Equip[13] + Buff[13] + VWisdom * Coefficient[13]; }
        }

        /// <summary>
        /// 获取魔法攻击力最大值
        /// </summary>
        public double VMagicMax
        {
            get { return ABase[14] + Equip[14] + Buff[14] + VWisdom * Coefficient[14]; }
        }

        /// <summary>
        /// 获取暴击率
        /// </summary>
        public double VBurst
        {
            get { return ABase[15] + Equip[15] + Buff[15] + VLucky * Coefficient[15]; }
        }

        /// <summary>
        /// 获取或设置当前活力值
        /// </summary>
        public double VEnergy;

        /// <summary>
        /// 获取或设置最大活力值
        /// </summary>
        public double VEnergyMax;

        /// <summary>
        /// 获取或设置属性基数
        /// 0-15对应基础属性值
        /// </summary>
        public double[] ABase;

        /// <summary>
        /// 获取或设置装备加成总和
        /// 0-15对应基础属性值
        /// 16-20对应5大属性
        /// </summary>
        public double[] Equip;

        /// <summary>
        /// 获取或设置加持/减持值总和
        /// 0-15对应基础属性值
        /// 16-20对应5大属性
        /// </summary>
        public double[] Buff;

        /// <summary>
        /// 获取或设置属性系数(成长率)
        /// 0-15对应基础属性值
        /// </summary>
        public double[] Coefficient;

        /// <summary>
        /// 获取或设置精灵属性潜能值
        /// </summary>
        public int VPotentialBase;

        /// <summary>
        /// 获取或设置力量基值
        /// </summary>
        public double VPowerBase;
        /// <summary>
        /// 获取或设置力量实际值
        /// 影响最大负重,物理攻击力(最小 - 最大)
        /// --[相关基值属性计算公式]:
        /// 最大负重 = ABase[0] + Equip[0] + Buff[0] + VPower * Coefficient[0]
        /// 物理攻击力最小值 = ABase[1] + Equip[1] + Buff[1] + VPower * Coefficient[1]
        /// 物理攻击力最大值 = ABase[2] + Equip[2] + Buff[2] + VPower * Coefficient[2]
        /// </summary>
        public double VPower { get { return VPowerBase + Equip[16] + Buff[16]; } }

        /// <summary>
        /// 获取或设置敏捷基值
        /// </summary>
        public double VAgileBase;
        /// <summary>
        /// 获取或设置敏捷实际值
        /// 影响命中,闪避,跑速,攻速,施法速度
        /// --[相关基值属性计算公式]:
        /// 命中 = ABase[3] + Equip[3] + Buff[3] + VAgile * Coefficient[3]
        /// 闪避 = ABase[4] + Equip[4] + Buff[4] + VAgile * Coefficient[4]
        /// 跑速 = ABase[5] - Equip[5] + Buff[5] - VAgile * Coefficient[5]
        /// 物攻速度 = ABase[6] - Equip[6] + Buff[6] - VAgile * Coefficient[6]
        /// 施法速度 = ABase[7] - Equip[7] + Buff[7] - VAgile * Coefficient[7]
        /// </summary>
        public double VAgile { get { return VAgileBase + Equip[17] + Buff[17]; } }

        /// <summary>
        /// 获取或设置体格基值
        /// </summary>
        public double VPhysiqueBase;
        /// <summary>
        /// 获取或设置体格实际值
        /// 影响最大生命值,物理防御力,格档率(与暴击率相反,物理或魔法攻击伤害减半)
        /// --[相关基值属性计算公式]:
        /// 最大生命值 = ABase[8] + Equip[8] + Buff[8] + VPhysique * Coefficient[8]
        /// 物理防御力 = ABase[9] + Equip[9] + Buff[9] + VPhysique * Coefficient[9]
        /// 格档率 = ABase[10] + Equip[10] + Buff[10] + VPhysique * Coefficient[10]
        /// </summary>
        public double VPhysique { get { return VPhysiqueBase + Equip[18] + Buff[18]; } }

        /// <summary>
        /// 获取或设置智慧基值
        /// </summary>
        public double VWisdomBase;
        /// <summary>
        /// 获取或设置智慧实际值
        /// 影响最大魔法值,魔法防御力,魔法攻击力(最小 - 最大)
        /// --[相关基值属性计算公式]:
        /// 最大魔法值 = ABase[11] + Equip[11] + Buff[11] + VWisdom * Coefficient[11]
        /// 魔法防御力 = ABase[12] + Equip[12] + Buff[12] + VWisdom * Coefficient[12]
        /// 魔法攻击力最小值 = ABase[13] + Equip[13] + Buff[13] + VWisdom * Coefficient[13]
        /// 魔法攻击力最大值 = ABase[14] + Equip[14] + Buff[14] + VWisdom * Coefficient[14]
        /// </summary>
        public double VWisdom { get { return VWisdomBase + Equip[19] + Buff[19]; } }

        /// <summary>
        /// 获取或设置幸运基值
        /// </summary>
        public double VLuckyBase;
        /// <summary>
        /// 获取或设置幸运实际值
        /// 影响暴击率(物理或魔法攻击加倍)及其他
        /// --[相关基值属性计算公式]:
        /// 暴击率 = ABase[15] + Equip[15] + Buff[15] + VLucky * ACoefficient[15]
        /// </summary>
        public double VLucky { get { return VLuckyBase + Equip[20] + Buff[20]; } }

        #endregion

        #region Field Region
        Vector2 mouseClickVector;
        XGame gameRef;
        readonly Character character;
        PathFinderFast pathFinder;
        MaskData maskData;
        Stack<Vector2> pathStack;
        Vector2 speedVector;
        LeaderFacePlate lfp;
        Manager manager;

        #endregion

        #region Property Region

        public Camera Camera;

        public AnimatedSprite Sprite
        {
            get { return character.Sprite; }
        }

        public Character Character
        {
            get { return character; }
        }

        #endregion

        #region Constructor Region

        public Player(Manager manager, XGame game, Character character, MaskData maskData, Texture2D fp, Texture2D face, Texture2D battle)
        {
            this.manager = manager;
            gameRef = game;
            Camera = new Camera();
            this.character = character;
            this.mouseClickVector = Vector2.Zero;
            this.maskData = maskData;
            speedVector = Vector2.Zero;
            //this.lfp = new LeaderFacePlate(manager, fp, face, battle, "XuXiang");
            //this.lfp.Position = new Vector2(20, 20);

            this.VLevel = 20;
            this.VLife = 3000;
            this.VMana = 1500;
            this.VEnergyMax = 100;
            this.VEnergy = 80;

            pathFinder = new PathFinderFast(maskData.Matrix);
            pathFinder.Formula = HeuristicFormula.Manhattan; //使用我个人觉得最快的曼哈顿A*算法
            pathFinder.HeavyDiagonals = true; //使用对角线移动
            pathFinder.HeuristicEstimate = 0;
            pathFinder.SearchLimit = 200000;
        }

        #endregion

        #region Method Region

        private Stack<Vector2> GetPathStack(Vector2 from, Vector2 to)
        {
            List<PathFinderNode> path = pathFinder.FindPath(from / maskData.CellSize, to / maskData.CellSize);
            Stack<Vector2> pathStack = new Stack<Vector2>(path.Count); //定义关键帧坐标集
            for (int i = 0; i < path.Count; i++)
            {
                //从起点开始以GridSize为单位，顺序填充关键帧坐标集，并进行坐标系放大
                pathStack.Push(new Vector2(path[i].X * maskData.CellSize + from.X % maskData.CellSize, path[i].Y * maskData.CellSize + from.Y % maskData.CellSize));
            }
            return pathStack;
        }

        private bool ExistPath(Vector2 from, Vector2 to)
        {
            return pathFinder.FindPath(from / maskData.CellSize, to / maskData.CellSize) != null;
        }

        public void Update(GameTime gameTime)
        {
            Camera.Update(gameTime);
            Sprite.Update(gameTime);
            //lfp.Update(this.VLevel, true, 5000, this.VLife, 2000, this.VMana, this.VEnergyMax, this.VEnergy);





            MouseState state = InputHandler.MouseState;
            Vector2 clickvec = new Vector2(Camera.Position.X + state.X/ Camera.Zoom, Camera.Position.Y + state.Y/ Camera.Zoom) ;
            clickvec = Sprite.LockToMap(clickvec);
            if (InputHandler.MouseReleased(manager, InputHandler.MouseKey.LeftKey) &&
                !(clickvec == this.mouseClickVector) && !(clickvec == this.Sprite.Position))
            {
                if (ExistPath(Sprite.Position, clickvec) == true)
                {
                    mouseClickVector = clickvec;
                    Sprite.State = Animation.State.Run;
                    pathStack = null;
                }
            }
            if (Sprite.State == Animation.State.Run)
            {
                //直线移动
                Vector2 distance = mouseClickVector - Sprite.Position;
                float speed = Sprite.Speed * (float)gameTime.ElapsedGameTime.TotalSeconds;
                if (distance == Vector2.Zero || distance.Length() <= speed || (pathStack != null && pathStack.Count == 0))
                {
                    //如果不是完全重合，需要得出速度矢量对方向作出调整，
                    if (distance != Vector2.Zero)
                    {
                        distance.Normalize();
                        this.speedVector = distance * speed;
                    }
                    //如果距离过小，直接移动过去。
                    Sprite.Position = mouseClickVector;
                    Sprite.State = Animation.State.Stand;
                    pathStack = null;
                }
                else
                {
                    distance.Normalize();
                    this.speedVector = distance * speed;
                    Vector2 tmp = Sprite.Position + this.speedVector;
                    if (pathStack == null && maskData.IsObstacle(tmp.X, tmp.Y) == false)
                    {
                        //直线移动
                        Sprite.Position = tmp;
                    }
                    else
                    {
                        if (pathStack == null)
                        {
                            pathStack = GetPathStack(Sprite.Position, mouseClickVector);
                        }
                        if (pathStack.Peek() == Sprite.Position)
                            pathStack.Pop();
                        //A*移动

                        //如果是最后一格，直接导向mouseClickVector，以免精灵方向不对
                        if (pathStack.Count == 1)
                            this.speedVector = mouseClickVector - Sprite.Position;
                        else
                            this.speedVector = pathStack.Peek() - Sprite.Position;

                        this.speedVector.Normalize();
                        this.speedVector *= speed;
                        Sprite.Position += this.speedVector;
                        if (Vector2.Distance(Sprite.Position, pathStack.Peek()) < this.speedVector.Length())
                        {
                            pathStack.Pop();
                        }
                    }
                }
                Sprite.Direction = Animation.GetDirectionByTan(Vector2.Zero, speedVector);

            }
            //Sprite.LockToMap(Camera.Position.X, Camera.Position.Y);

            int delta = InputHandler.GetScrollWheelValueDelta();
            if (delta > 0)
            {
                for (int i = delta; i > 0; i = i - 120)
                    Camera.ZoomIn();
            }
            else if (delta < 0)
            {
                for (int i = delta; i < 0; i = i + 120)
                    Camera.ZoomOut();
            }

            if (Camera.CameraMode == CameraMode.Follow)
                Camera.LockToSprite(Sprite);
        }

        public void Draw(GameTime gameTime, GraphicsDevice graphicsDevice, SpriteBatch spriteBatch)
        {
            character.Draw(gameTime, spriteBatch, this.Camera.Position.X, this.Camera.Position.Y, this.Camera.Zoom);
            //lfp.Draw(graphicsDevice, spriteBatch);
        }

        #endregion
    }
}
